package io.github.weiranyi;

import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class MyIoc {
    public static void main(String[] args) throws Exception {
        // 一、初始化
        // 1.读取配置信息
        Properties properties = new Properties();
        properties.load(MyIoc.class.getResourceAsStream("/ioc.properties")); //{orderService=io.github.weiranyi.OrderService, orderDao=io.github.weiranyi.OrderDao}
        // 2.创建一个容器：存储名字到对象的映射
        Map<String, Object> beans = new HashMap<>();

        // 3.通过反射创建对象，丢进hashmap容器中
        properties.forEach((beanName, beanClass) -> {
            try {
                Class klass = Class.forName((String) beanClass);
                Object beanInstance = klass.getConstructor().newInstance();
                beans.put((String) beanName, beanInstance);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });

        // 二、依赖关系
        beans.forEach((beanName, beanInstance) -> {
            dependencyInject(beanName, beanInstance, beans);
        });

        // 三、获取
        WeiranyiService weiranyiService = (WeiranyiService) beans.get("weiranyiService");
        WeiranyiDao weiranyiDao = (WeiranyiDao) beans.get("weiranyiDao");
        weiranyiDao.select();
        System.out.println();
    }

    // 依赖注入
    private static void dependencyInject(String beanName, Object beanInstance, Map<String, Object> beans) {
        // 拿到被Autowired标记的字段,进行自动装配
        List<Field> fieldsToBeAutowired = Stream.of(beanInstance.getClass().getDeclaredFields())
                .filter(field -> field.getAnnotation(Autowired.class) != null)
                .collect(Collectors.toList());

        fieldsToBeAutowired.forEach(field -> {
            // 获取依赖对象的实例
            String fieldName = field.getName();
            Object dependencyBeanInstance = beans.get(fieldName);
            try {
                field.setAccessible(true);
                field.set(beanInstance, dependencyBeanInstance);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        });
    }
}
